package cn.jn.lhm.part07;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.*;

/**
 * @author lhm 2753914576@qq.com
 * @time 2024/10/17 - 下午9:30
 **/
public class Server {

    private int port;


    /**
     * Main Reactor
     */
    private Acceptor acceptor;

    /**
     * Sub Reactors
     */
    private Set<PollerIO> pollerIOSet;


    /**
     * Worker Pool
     */
    private ExecutorService executorService;


    /**
     * Server Status
     */
    private volatile boolean stopped = false;


    public void init() {
        // init by config
        this.port = 9999;

        // init Sub Reactors: min 4
        int ioNums = Math.max(4, Runtime.getRuntime().availableProcessors() * 2);
        pollerIOSet = new HashSet<>(ioNums);
        for (int i = 0; i < ioNums; i++) {
            pollerIOSet.add(new PollerIO("PollerIO-" + i, this));
        }

        // init Main Reactor
        // ready accept request
        try {
            this.acceptor = new Acceptor(" Main Reactor", this, pollerIOSet);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    public void start() {
        this.executorService = new ThreadPoolExecutor(10, 10, 60, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(1024));
        //  Sub Reactors start
        this.pollerIOSet.forEach(Thread::start);

        // Main Reactor start
        this.acceptor.start();
    }

    public void shutdown() {
        // Main Reactor stop
        // all Sub Reactors stop
        this.stopped = true;

        this.executorService.shutdown();
    }


    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(1);

        Server server = new Server();
        server.init();
        server.start();

        // stop --- JVM shutdown hook
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            server.shutdown();
            countDownLatch.countDown();
        }));


        try {
            countDownLatch.await();
            System.out.println("server closed");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    public void addBuTask(BuTask task) {
        this.executorService.execute(task);
    }

    public int getPort() {
        return port;
    }

    public boolean isStopped() {
        return stopped;
    }
}
